This notebook was written as part of manuscript revisions. Here, we explore how quanTIseq-related results might change if only tumors at a certain level of known tumor purity (tumor_fraction metadata variable) are considered. Only stranded RNA data is considered here, as in the manuscript.
The associated issue for this exploration is here: https://github.com/AlexsLemonade/OpenPBTA-analysis/issues/1628
Set directories and files
root_dir <- rprojroot::find_root(rprojroot::has_dir(".git"))
quantiseq_dir <- file.path(root_dir, "analyses", "immune-deconv")
data_dir <- file.path(root_dir, "data")
palette_file <- file.path(root_dir, "figures", "palettes", "broad_histology_cancer_group_palette.tsv")
metadata_file <- file.path(data_dir, "pbta-histologies.tsv")
quantiseq_file <- file.path(quantiseq_dir, "results", "quantiseq_deconv-output-thresholded.rds")
# output plot file:
quantiseq_plot_pdf <- file.path(quantiseq_dir, "plots", "tumor-purity-threshold_quantiseq-cancer-groups.pdf")
Read in and prep data:
quantiseq_raw_df <- read_rds(quantiseq_file)
metadata_df <- read_tsv(metadata_file, guess_max = 10000)
Parsed with column specification:
cols(
.default = col_character(),
OS_days = [32mcol_double()[39m,
age_last_update_days = [32mcol_double()[39m,
normal_fraction = [32mcol_double()[39m,
tumor_fraction = [32mcol_double()[39m,
tumor_ploidy = [32mcol_double()[39m
)
See spec(...) for full column specifications.
palette_df <- read_tsv(palette_file)
Parsed with column specification:
cols(
broad_histology = [31mcol_character()[39m,
cancer_group = [31mcol_character()[39m,
broad_histology_display = [31mcol_character()[39m,
cancer_group_display = [31mcol_character()[39m,
broad_histology_hex = [31mcol_character()[39m,
cancer_group_abbreviation = [31mcol_character()[39m,
cancer_group_hex = [31mcol_character()[39m,
broad_histology_order = [32mcol_double()[39m,
oncoprint_group = [31mcol_character()[39m,
oncoprint_main = [33mcol_logical()[39m
)
# These are the groups we highlight in the manuscript
cancer_groups_of_interest <- c("Pilocytic astrocytoma",
"Diffuse midline glioma",
"Craniopharyngioma",
"Ganglioglioma",
"Ependymoma",
"Medulloblastoma",
"Schwannoma",
"Neurofibroma Plexiform",
"Other embryonal tumor",
"Atypical Teratoid Rhabdoid Tumor",
"Meningioma",
"Dysembryoplastic neuroepithelial tumor")
# Combine with cancer group and palette info
quantiseq_df <- quantiseq_raw_df %>%
select(-library, -method) %>%
rename(Kids_First_Biospecimen_ID = sample) %>%
inner_join(
select(
metadata_df,
cancer_group,
Kids_First_Biospecimen_ID
)
) %>%
inner_join(
select(
palette_df,
cancer_group,
cancer_group_display,
cancer_group_hex
)
) %>%
select(-cancer_group) %>%
# Filter to relevant rows as in MS figure
filter(cell_type != "uncharacterized cell") %>%
filter(cancer_group_display %in% cancer_groups_of_interest)
Joining, by = "Kids_First_Biospecimen_ID"
Joining, by = "cancer_group"
Re-generate plots
Here we will re-make the two quanTIseq plots:
- First the immune fractions across cancer groups for each cell type
- Second the CD8/CD4 ratio for molecular subtypes of interest. Note that there are far fewer subtypes that get plotted here due to the threshold filtering!
For reference, we also include the original (without thresholding) plots below each.
Immune fractions across cancer groups
# plot by cancer group groups of interest, where cancer groups are ordered
# in the same order as the original plot for ease of comparison
cancer_group_order <- c("Pilocytic astrocytoma",
"Medulloblastoma",
"Ependymoma",
"Diffuse midline glioma",
"Ganglioglioma",
"Craniopharyngioma",
"Other embryonal tumor",
"Atypical Teratoid Rhabdoid Tumor",
"Meningioma",
"Dysembryoplastic neuroepithelial tumor",
"Neurofibroma Plexiform",
"Schwannoma"
)
quantiseq_plot <- quantiseq_df %>%
# order the `cancer_group_display` variable by the vector above
mutate(cancer_group_display = fct_relevel(cancer_group_display, cancer_group_order),
# wrap labels so they fit in strips
cancer_group_display = fct_relabel(cancer_group_display, stringr::str_wrap, 30)
) %>%
# and into the plot
ggplot() +
aes(x = cell_type,
y = score,
color = cancer_group_hex) +
geom_jitter(width = 0.15, size = 1, alpha = 0.7) +
geom_boxplot(outlier.size = 0,
size = 0.2,
color = "black",
alpha = 0,
# remove whiskers
coef = 0) +
facet_wrap(~cancer_group_display, nrow = 2, scales = "free_y") +
scale_color_identity() +
labs(
x = "Immune cell",
y = "Estimated fraction in sample"
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1, size = 7),
axis.text.y = element_text(size = 9),
strip.text = element_text(size = 8)
)
quantiseq_plot

We’ll export this figure:
ggsave(
quantiseq_plot_pdf,
quantiseq_plot,
width = 12,
height = 4.5
)
Original plot (without thresholding)
The relevant plot is Panel C.

CD8/CD4 ratios
# Find molecular subtypes, and their order, to include in this panel
broad_histology_order <- c("Tumor of sellar region", "Ependymal tumor", "Embryonal tumor", "High-grade glioma")
subtype_order <- palette_df %>%
inner_join(
select(metadata_df,
broad_histology,
molecular_subtype)
) %>%
select(broad_histology_display, molecular_subtype) %>%
# keep only relevant histologies
filter(broad_histology_display %in% broad_histology_order) %>%
# remove NA and unclassified subtypes
filter(!is.na(molecular_subtype),
!str_detect(molecular_subtype, "To be classified")) %>%
# Keep only combinations with N>=3
count(broad_histology_display, molecular_subtype) %>%
filter(n >= 3) %>%
# Factor/arrange broad_histology_display to obtain the final molecular_subtype order
mutate(broad_histology_display = fct_relevel(broad_histology_display, broad_histology_order)) %>%
arrange(broad_histology_display) %>%
pull(molecular_subtype)
Joining, by = "broad_histology"
Unknown levels in `f`: Ependymal tumor
# Calculate cd8+/cd4+ ratio for all subtypes, join with subtype/histology, and set up factors
ratio_df <- quantiseq_df %>%
spread(cell_type, score) %>%
mutate(cd8_cd4_ratio = `T cell CD8+` / `T cell CD4+ (non-regulatory)`) %>%
select(Kids_First_Biospecimen_ID, cd8_cd4_ratio) %>%
# Keep only the known ratios
filter(!(is.infinite(cd8_cd4_ratio)),
!(is.nan(cd8_cd4_ratio))) %>%
# Join with subtypes
inner_join(
select(metadata_df,
Kids_First_Biospecimen_ID,
broad_histology,
molecular_subtype)
) %>%
# Filter to subtype_order set up for Figure S6E
filter(molecular_subtype %in% subtype_order)
Joining, by = "Kids_First_Biospecimen_ID"
# Plot
ggplot(ratio_df) +
aes(x = molecular_subtype,
y = cd8_cd4_ratio) +
# remove outliers
geom_boxplot(outlier.shape = NA, color = "grey40", size = 0.5) +
geom_jitter(width = 0.1, size = 2, alpha = 0.6) +
labs(x = "Molecular subtype of tumor sample",
y = "Ratio of CD8+/CD4+ T cell fractions") +
theme(axis.text.x = element_text(hjust = 1,
angle = 30,
size = 6))

Original plot (without thresholding)
The relevant plot is Panel F

Assess plots
Now, we will re-assess specific results we report in the manuscript. Specifically, these are the parts of the manuscript sentences below that reference either Figure 5C or Figure S6F.
Result 1
https://github.com/AlexsLemonade/OpenPBTA-manuscript/blob/b0fdf6f24fe9c021f22e8b7da348708f68877ee5/content/03.results.md?plain=1#L277-L278
Schwannomas and neurofibromas, which have a documented inflammatory immune microenvironment of T and B lymphocytes as well as tumor-associated macrophages (TAMs), are driven by upregulation of cytokines such as IFN\(\gamma\), IL-1, and IL-6, and TNF\(\alpha\) [@doi:10.1093/noajnl/vdaa023]. Indeed, we observed significant upregulation of these cytokines in GSVA hallmark pathways (Bonferroni-corrected p < 0.05) (Figure {@fig:Fig5}B) and found immune cell types dominated by monocytes in these tumors (Figure {@fig:Fig5}C).
The first plot above recapitulates the result that monocytes are dominant in schwannomas and neurofibromas. The thresholded results are consistent.
Result 2
https://github.com/AlexsLemonade/OpenPBTA-manuscript/blob/b0fdf6f24fe9c021f22e8b7da348708f68877ee5/content/03.results.md?plain=1#L282
Although CD8+ T-cell infiltration across all cancer groups was quite low (Figure {@fig:Fig5}C), we observed some signal in specific cancer molecular subtypes (Groups 3 and 4 medulloblastoma) as well as outlier tumors (BRAF-driven LGG, BRAF-driven and wildtype ganglioglioma, and CNS embryonal NOS; Figure {@fig:S6}E)
The first plot shows that CD8+ T-cell infiltration across all cancer groups remains quite low. The second plot shows the MB 3/4 signal, but there are no longer any outliers. The thresholded results are consistent, and differences may be explained by sample size/power.
Result 3
https://github.com/AlexsLemonade/OpenPBTA-manuscript/blob/b0fdf6f24fe9c021f22e8b7da348708f68877ee5/content/03.results.md?plain=1#L283
Surprisingly, the classically immunologically-cold HGG and DMG tumors [@doi:10.1186/s40478-018-0553-x; @doi:10.1093/brain/awab155] contained higher overall fractions of immune cells, where monocytes, dendritic cells, and NK cells were the most prevalent (Figure {@fig:Fig5}C).
The first plot shows that for DMG, overall fractions fall in ranges that are consistent with other cancer groups, so “higher overall fractions” are no longer the case. This difference may be a consequence of reduced sample size overall for this re-analysis. DMGs are dominated by monocytes, dendritic cells, and NK cells, which is consistent with previous results.
However, as we did not actually plot other HGG groups here, we may wish to revise this statement to focus more on the panels that are actually in the plot more generally.
Result 4
https://github.com/AlexsLemonade/OpenPBTA-manuscript/blob/b0fdf6f24fe9c021f22e8b7da348708f68877ee5/content/03.results.md?plain=1#L292
While adamantinomatous craniopharyngiomas and Group 3 and Group 4 medulloblastomas had the highest CD8+ to CD4+ T cell ratios (Figure {@fig:S6}F), very few tumors had ratios greater than 1, highlighting an urgent need to identify novel therapeutics for these immunologically-cold pediatric brain tumors with poor prognosis.
As noted, the second plot itself has fewer subtypes, which is expected with a filtered dataset. Of note, the CRANIO, ADAM molecular subtype is no longer present. We again see that MB groups 3 and 4 have higher values with other molecular subtypes around 0, which is consistent with the original results.
Conclusions
Overall, quanTIseq results are broadly consistent after thresholding.
Session Info
sessionInfo()
R version 3.6.0 (2019-04-26)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux 9 (stretch)
Matrix products: default
BLAS/LAPACK: /usr/lib/libopenblasp-r0.2.19.so
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=C LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] forcats_0.4.0 stringr_1.4.0 dplyr_0.8.3 purrr_0.3.2 readr_1.3.1 tidyr_0.8.3
[7] tibble_2.1.3 ggplot2_3.2.0 tidyverse_1.2.1
loaded via a namespace (and not attached):
[1] tidyselect_0.2.5 xfun_0.8 haven_2.1.1 lattice_0.20-38 colorspace_1.4-1 generics_0.0.2
[7] htmltools_0.3.6 yaml_2.2.0 base64enc_0.1-3 rlang_0.4.0 ggpubr_0.2.1 pillar_1.4.2
[13] glue_1.3.1 withr_2.1.2 modelr_0.1.4 readxl_1.3.1 munsell_0.5.0 ggsignif_0.5.0
[19] gtable_0.3.0 cellranger_1.1.0 rvest_0.3.4 evaluate_0.14 labeling_0.3 knitr_1.23
[25] broom_0.5.2 Rcpp_1.0.1 backports_1.1.4 scales_1.0.0 jsonlite_1.6 hms_0.4.2
[31] digest_0.6.20 stringi_1.4.3 grid_3.6.0 rprojroot_1.3-2 cli_1.1.0 tools_3.6.0
[37] magrittr_1.5 lazyeval_0.2.2 crayon_1.3.4 pkgconfig_2.0.2 xml2_1.2.0 lubridate_1.7.4
[43] assertthat_0.2.1 rmarkdown_1.13 httr_1.4.0 rstudioapi_0.10 R6_2.4.0 nlme_3.1-140
[49] compiler_3.6.0
LS0tCnRpdGxlOiAiQXNzZXNzIHF1YW5USXNlcSByZXN1bHRzIGNhbGN1bGF0ZWQgd2l0aCB0dW1vciBwdXJpdHkgdGhyZXNob2xkZWQgZGF0YSIKYXV0aG9yOiAiU0ogU3BpZWxtYW4gZm9yIENDREwiCmRhdGU6ICIyMDIzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgdG9jOiBUUlVFCnRvY19mbG9hdDogVFJVRQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlID0gRkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQp0aGVtZV9zZXQoZ2dwdWJyOjp0aGVtZV9wdWJyKCkpIApzZXQuc2VlZCgyMDIzKQpgYGAKCgpUaGlzIG5vdGVib29rIHdhcyB3cml0dGVuIGFzIHBhcnQgb2YgbWFudXNjcmlwdCByZXZpc2lvbnMuCkhlcmUsIHdlIGV4cGxvcmUgaG93IGBxdWFuVElzZXFgLXJlbGF0ZWQgcmVzdWx0cyBtaWdodCBjaGFuZ2UgaWYgb25seSB0dW1vcnMgYXQgYSBjZXJ0YWluIGxldmVsIG9mIGtub3duIHR1bW9yIHB1cml0eSAoYHR1bW9yX2ZyYWN0aW9uYCBtZXRhZGF0YSB2YXJpYWJsZSkgYXJlIGNvbnNpZGVyZWQuCk9ubHkgc3RyYW5kZWQgUk5BIGRhdGEgaXMgY29uc2lkZXJlZCBoZXJlLCBhcyBpbiB0aGUgbWFudXNjcmlwdC4KClRoZSBhc3NvY2lhdGVkIGlzc3VlIGZvciB0aGlzIGV4cGxvcmF0aW9uIGlzIGhlcmU6IGh0dHBzOi8vZ2l0aHViLmNvbS9BbGV4c0xlbW9uYWRlL09wZW5QQlRBLWFuYWx5c2lzL2lzc3Vlcy8xNjI4CgoKCiMjIFNldCBkaXJlY3RvcmllcyBhbmQgZmlsZXMKCmBgYHtyfQpyb290X2RpciA8LSBycHJvanJvb3Q6OmZpbmRfcm9vdChycHJvanJvb3Q6Omhhc19kaXIoIi5naXQiKSkKcXVhbnRpc2VxX2RpciA8LSBmaWxlLnBhdGgocm9vdF9kaXIsICJhbmFseXNlcyIsICJpbW11bmUtZGVjb252IikKZGF0YV9kaXIgPC0gZmlsZS5wYXRoKHJvb3RfZGlyLCAiZGF0YSIpCnBhbGV0dGVfZmlsZSA8LSBmaWxlLnBhdGgocm9vdF9kaXIsICJmaWd1cmVzIiwgInBhbGV0dGVzIiwgImJyb2FkX2hpc3RvbG9neV9jYW5jZXJfZ3JvdXBfcGFsZXR0ZS50c3YiKQptZXRhZGF0YV9maWxlIDwtIGZpbGUucGF0aChkYXRhX2RpciwgInBidGEtaGlzdG9sb2dpZXMudHN2IikKcXVhbnRpc2VxX2ZpbGUgPC0gZmlsZS5wYXRoKHF1YW50aXNlcV9kaXIsICJyZXN1bHRzIiwgInF1YW50aXNlcV9kZWNvbnYtb3V0cHV0LXRocmVzaG9sZGVkLnJkcyIpCgojIG91dHB1dCBwbG90IGZpbGU6CnF1YW50aXNlcV9wbG90X3BkZiA8LSBmaWxlLnBhdGgocXVhbnRpc2VxX2RpciwgInBsb3RzIiwgInR1bW9yLXB1cml0eS10aHJlc2hvbGRfcXVhbnRpc2VxLWNhbmNlci1ncm91cHMucGRmIikKYGBgCgoKUmVhZCBpbiBhbmQgcHJlcCBkYXRhOgoKYGBge3J9CnF1YW50aXNlcV9yYXdfZGYgPC0gcmVhZF9yZHMocXVhbnRpc2VxX2ZpbGUpCm1ldGFkYXRhX2RmIDwtIHJlYWRfdHN2KG1ldGFkYXRhX2ZpbGUsIGd1ZXNzX21heCA9IDEwMDAwKQpwYWxldHRlX2RmIDwtIHJlYWRfdHN2KHBhbGV0dGVfZmlsZSkKCiMgVGhlc2UgYXJlIHRoZSBncm91cHMgd2UgaGlnaGxpZ2h0IGluIHRoZSBtYW51c2NyaXB0CmNhbmNlcl9ncm91cHNfb2ZfaW50ZXJlc3QgPC0gYygiUGlsb2N5dGljIGFzdHJvY3l0b21hIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlmZnVzZSBtaWRsaW5lIGdsaW9tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3JhbmlvcGhhcnluZ2lvbWEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHYW5nbGlvZ2xpb21hIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFcGVuZHltb21hIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWVkdWxsb2JsYXN0b21hIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTY2h3YW5ub21hIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOZXVyb2ZpYnJvbWEgUGxleGlmb3JtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciBlbWJyeW9uYWwgdHVtb3IiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkF0eXBpY2FsIFRlcmF0b2lkIFJoYWJkb2lkIFR1bW9yIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZW5pbmdpb21hIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEeXNlbWJyeW9wbGFzdGljIG5ldXJvZXBpdGhlbGlhbCB0dW1vciIpCgojIENvbWJpbmUgd2l0aCBjYW5jZXIgZ3JvdXAgYW5kIHBhbGV0dGUgaW5mbwpxdWFudGlzZXFfZGYgPC0gcXVhbnRpc2VxX3Jhd19kZiAlPiUKICBzZWxlY3QoLWxpYnJhcnksIC1tZXRob2QpICU+JQogIHJlbmFtZShLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEID0gc2FtcGxlKSAlPiUKICBpbm5lcl9qb2luKAogICAgc2VsZWN0KAogICAgICBtZXRhZGF0YV9kZiwgCiAgICAgIGNhbmNlcl9ncm91cCwgCiAgICAgIEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQKICAgICkKICApICU+JQogIGlubmVyX2pvaW4oCiAgICBzZWxlY3QoCiAgICAgIHBhbGV0dGVfZGYsIAogICAgICBjYW5jZXJfZ3JvdXAsCiAgICAgIGNhbmNlcl9ncm91cF9kaXNwbGF5LCAKICAgICAgY2FuY2VyX2dyb3VwX2hleAogICAgKQogICkgJT4lCiAgc2VsZWN0KC1jYW5jZXJfZ3JvdXApICU+JQogICMgRmlsdGVyIHRvIHJlbGV2YW50IHJvd3MgYXMgaW4gTVMgZmlndXJlCiAgZmlsdGVyKGNlbGxfdHlwZSAhPSAidW5jaGFyYWN0ZXJpemVkIGNlbGwiKSAlPiUKICBmaWx0ZXIoY2FuY2VyX2dyb3VwX2Rpc3BsYXkgJWluJSBjYW5jZXJfZ3JvdXBzX29mX2ludGVyZXN0KQpgYGAKCiMjIFJlLWdlbmVyYXRlIHBsb3RzCgpIZXJlIHdlIHdpbGwgcmUtbWFrZSB0aGUgdHdvIGBxdWFuVElzZXFgIHBsb3RzOgoKLSBGaXJzdCB0aGUgaW1tdW5lIGZyYWN0aW9ucyBhY3Jvc3MgY2FuY2VyIGdyb3VwcyBmb3IgZWFjaCBjZWxsIHR5cGUKLSBTZWNvbmQgdGhlIENEOC9DRDQgcmF0aW8gZm9yIG1vbGVjdWxhciBzdWJ0eXBlcyBvZiBpbnRlcmVzdC4KTm90ZSB0aGF0IHRoZXJlIGFyZSBfZmFyIGZld2VyIHN1YnR5cGVzXyB0aGF0IGdldCBwbG90dGVkIGhlcmUgZHVlIHRvIHRoZSB0aHJlc2hvbGQgZmlsdGVyaW5nIQoKRm9yIHJlZmVyZW5jZSwgd2UgYWxzbyBpbmNsdWRlIHRoZSBfb3JpZ2luYWxfICh3aXRob3V0IHRocmVzaG9sZGluZykgcGxvdHMgYmVsb3cgZWFjaC4gCgojIyMgSW1tdW5lIGZyYWN0aW9ucyBhY3Jvc3MgY2FuY2VyIGdyb3VwcwoKCmBgYHtyLCBmaWcud2lkdGggPSAxNiwgZmlnLmhlaWdodCA9IDR9CiMgcGxvdCBieSBjYW5jZXIgZ3JvdXAgZ3JvdXBzIG9mIGludGVyZXN0LCB3aGVyZSBjYW5jZXIgZ3JvdXBzIGFyZSBvcmRlcmVkIAojICBpbiB0aGUgc2FtZSBvcmRlciBhcyB0aGUgb3JpZ2luYWwgcGxvdCBmb3IgZWFzZSBvZiBjb21wYXJpc29uCgpjYW5jZXJfZ3JvdXBfb3JkZXIgPC0gYygiUGlsb2N5dGljIGFzdHJvY3l0b21hIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJNZWR1bGxvYmxhc3RvbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAiRXBlbmR5bW9tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICJEaWZmdXNlIG1pZGxpbmUgZ2xpb21hIiwKICAgICAgICAgICAgICAgICAgICAgICAgIkdhbmdsaW9nbGlvbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAiQ3JhbmlvcGhhcnluZ2lvbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXIgZW1icnlvbmFsIHR1bW9yIiwKICAgICAgICAgICAgICAgICAgICAgICAgIkF0eXBpY2FsIFRlcmF0b2lkIFJoYWJkb2lkIFR1bW9yIiwKICAgICAgICAgICAgICAgICAgICAgICAgIk1lbmluZ2lvbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAiRHlzZW1icnlvcGxhc3RpYyBuZXVyb2VwaXRoZWxpYWwgdHVtb3IiLAogICAgICAgICAgICAgICAgICAgICAgICAiTmV1cm9maWJyb21hIFBsZXhpZm9ybSIsCiAgICAgICAgICAgICAgICAgICAgICAgICJTY2h3YW5ub21hIgogICAgICAgICAgICAgICAgICAgICAgICApCgpxdWFudGlzZXFfcGxvdCA8LSBxdWFudGlzZXFfZGYgJT4lCiAgIyBvcmRlciB0aGUgYGNhbmNlcl9ncm91cF9kaXNwbGF5YCB2YXJpYWJsZSBieSB0aGUgdmVjdG9yIGFib3ZlCiAgbXV0YXRlKGNhbmNlcl9ncm91cF9kaXNwbGF5ID0gZmN0X3JlbGV2ZWwoY2FuY2VyX2dyb3VwX2Rpc3BsYXksIGNhbmNlcl9ncm91cF9vcmRlciksCiAgICAgICAgICMgd3JhcCBsYWJlbHMgc28gdGhleSBmaXQgaW4gc3RyaXBzIAogICAgICAgICBjYW5jZXJfZ3JvdXBfZGlzcGxheSA9IGZjdF9yZWxhYmVsKGNhbmNlcl9ncm91cF9kaXNwbGF5LCBzdHJpbmdyOjpzdHJfd3JhcCwgMzApCiAgICAgICAgICkgJT4lCiAgIyBhbmQgaW50byB0aGUgcGxvdAogIGdncGxvdCgpICsgCiAgYWVzKHggPSBjZWxsX3R5cGUsIAogICAgICB5ID0gc2NvcmUsIAogICAgICBjb2xvciA9IGNhbmNlcl9ncm91cF9oZXgpICsgCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjE1LCBzaXplID0gMSwgYWxwaGEgPSAwLjcpICsgCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2l6ZSA9IDAsIAogICAgICAgICAgICAgICBzaXplID0gMC4yLAogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIAogICAgICAgICAgICAgICBhbHBoYSA9IDAsCiAgICAgICAgICAgICAgICMgcmVtb3ZlIHdoaXNrZXJzCiAgICAgICAgICAgICAgIGNvZWYgPSAwKSArCiAgZmFjZXRfd3JhcCh+Y2FuY2VyX2dyb3VwX2Rpc3BsYXksIG5yb3cgPSAyLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHNjYWxlX2NvbG9yX2lkZW50aXR5KCkgKyAKICBsYWJzKAogICAgeCA9ICJJbW11bmUgY2VsbCIsIAogICAgeSA9ICJFc3RpbWF0ZWQgZnJhY3Rpb24gaW4gc2FtcGxlIgogICkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gNyksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KQogICkKCnF1YW50aXNlcV9wbG90CmBgYAoKV2UnbGwgZXhwb3J0IHRoaXMgZmlndXJlOgoKYGBge3J9Cmdnc2F2ZSgKICBxdWFudGlzZXFfcGxvdF9wZGYsCiAgcXVhbnRpc2VxX3Bsb3QsCiAgd2lkdGggPSAxMiwKICBoZWlnaHQgPSA0LjUKKQpgYGAKCgojIyMjIE9yaWdpbmFsIHBsb3QgKHdpdGhvdXQgdGhyZXNob2xkaW5nKQoKVGhlIHJlbGV2YW50IHBsb3QgaXMgKipQYW5lbCBDKiouCgohW10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0FsZXhzTGVtb25hZGUvT3BlblBCVEEtYW5hbHlzaXMvNTg2ZDg3OGIyNWM4MDQ5NWEyNTQxMjkyYzJkOWIyODkxNjdmNmVjOS9maWd1cmVzL3BuZ3MvZmlndXJlNS5wbmcpCgoKCiMjIyBDRDgvQ0Q0IHJhdGlvcwoKCmBgYHtyfQojIEZpbmQgbW9sZWN1bGFyIHN1YnR5cGVzLCBhbmQgdGhlaXIgb3JkZXIsIHRvIGluY2x1ZGUgaW4gdGhpcyBwYW5lbApicm9hZF9oaXN0b2xvZ3lfb3JkZXIgPC0gYygiVHVtb3Igb2Ygc2VsbGFyIHJlZ2lvbiIsICJFcGVuZHltYWwgdHVtb3IiLCAiRW1icnlvbmFsIHR1bW9yIiwgIkhpZ2gtZ3JhZGUgZ2xpb21hIikKCnN1YnR5cGVfb3JkZXIgPC0gcGFsZXR0ZV9kZiAlPiUKICBpbm5lcl9qb2luKAogICAgc2VsZWN0KG1ldGFkYXRhX2RmLCAKICAgICAgICAgICBicm9hZF9oaXN0b2xvZ3ksIAogICAgICAgICAgIG1vbGVjdWxhcl9zdWJ0eXBlKQogICkgJT4lCiAgc2VsZWN0KGJyb2FkX2hpc3RvbG9neV9kaXNwbGF5LCBtb2xlY3VsYXJfc3VidHlwZSkgJT4lCiAgIyBrZWVwIG9ubHkgcmVsZXZhbnQgaGlzdG9sb2dpZXMKICBmaWx0ZXIoYnJvYWRfaGlzdG9sb2d5X2Rpc3BsYXkgJWluJSBicm9hZF9oaXN0b2xvZ3lfb3JkZXIpICU+JQogICMgcmVtb3ZlIE5BIGFuZCB1bmNsYXNzaWZpZWQgc3VidHlwZXMKICBmaWx0ZXIoIWlzLm5hKG1vbGVjdWxhcl9zdWJ0eXBlKSwKICAgICAgICAgIXN0cl9kZXRlY3QobW9sZWN1bGFyX3N1YnR5cGUsICJUbyBiZSBjbGFzc2lmaWVkIikpICU+JQogICMgS2VlcCBvbmx5IGNvbWJpbmF0aW9ucyB3aXRoIE4+PTMKICBjb3VudChicm9hZF9oaXN0b2xvZ3lfZGlzcGxheSwgbW9sZWN1bGFyX3N1YnR5cGUpICU+JSAKICBmaWx0ZXIobiA+PSAzKSAlPiUKICAjIEZhY3Rvci9hcnJhbmdlIGJyb2FkX2hpc3RvbG9neV9kaXNwbGF5IHRvIG9idGFpbiB0aGUgZmluYWwgbW9sZWN1bGFyX3N1YnR5cGUgb3JkZXIKICBtdXRhdGUoYnJvYWRfaGlzdG9sb2d5X2Rpc3BsYXkgPSBmY3RfcmVsZXZlbChicm9hZF9oaXN0b2xvZ3lfZGlzcGxheSwgYnJvYWRfaGlzdG9sb2d5X29yZGVyKSkgJT4lCiAgYXJyYW5nZShicm9hZF9oaXN0b2xvZ3lfZGlzcGxheSkgJT4lCiAgcHVsbChtb2xlY3VsYXJfc3VidHlwZSkKCgojIENhbGN1bGF0ZSBjZDgrL2NkNCsgcmF0aW8gZm9yIGFsbCBzdWJ0eXBlcywgam9pbiB3aXRoIHN1YnR5cGUvaGlzdG9sb2d5LCBhbmQgc2V0IHVwIGZhY3RvcnMKcmF0aW9fZGYgPC0gcXVhbnRpc2VxX2RmICU+JQogIHNwcmVhZChjZWxsX3R5cGUsIHNjb3JlKSAlPiUgCiAgbXV0YXRlKGNkOF9jZDRfcmF0aW8gPSBgVCBjZWxsIENEOCtgIC8gYFQgY2VsbCBDRDQrIChub24tcmVndWxhdG9yeSlgKSAgJT4lCiAgc2VsZWN0KEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQsIGNkOF9jZDRfcmF0aW8pICU+JQogICMgS2VlcCBvbmx5IHRoZSBrbm93biByYXRpb3MKICBmaWx0ZXIoIShpcy5pbmZpbml0ZShjZDhfY2Q0X3JhdGlvKSksIAogICAgICAgICAhKGlzLm5hbihjZDhfY2Q0X3JhdGlvKSkpICU+JQogICMgSm9pbiB3aXRoIHN1YnR5cGVzCiAgIGlubmVyX2pvaW4oCiAgICBzZWxlY3QobWV0YWRhdGFfZGYsIAogICAgICAgICAgIEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQsIAogICAgICAgICAgIGJyb2FkX2hpc3RvbG9neSwgCiAgICAgICAgICAgbW9sZWN1bGFyX3N1YnR5cGUpCiAgKSAlPiUKICAjIEZpbHRlciB0byBzdWJ0eXBlX29yZGVyIHNldCB1cCBmb3IgRmlndXJlIFM2RQogIGZpbHRlcihtb2xlY3VsYXJfc3VidHlwZSAlaW4lIHN1YnR5cGVfb3JkZXIpCmBgYAoKYGBge3J9CiMgUGxvdApnZ3Bsb3QocmF0aW9fZGYpICsgCiAgYWVzKHggPSBtb2xlY3VsYXJfc3VidHlwZSwKICAgICAgeSA9IGNkOF9jZDRfcmF0aW8pICsKICAjIHJlbW92ZSBvdXRsaWVycwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIGNvbG9yID0gImdyZXk0MCIsIHNpemUgPSAwLjUpICsgCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjEsIHNpemUgPSAyLCBhbHBoYSA9IDAuNikgKwogIGxhYnMoeCA9ICJNb2xlY3VsYXIgc3VidHlwZSBvZiB0dW1vciBzYW1wbGUiLAogICAgICAgeSA9ICJSYXRpbyBvZiBDRDgrL0NENCsgVCBjZWxsIGZyYWN0aW9ucyIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZ2xlID0gMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDYpKQoKYGBgCgoKCiMjIyMgT3JpZ2luYWwgcGxvdCAod2l0aG91dCB0aHJlc2hvbGRpbmcpClRoZSByZWxldmFudCBwbG90IGlzICoqUGFuZWwgRioqCgohW10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0FsZXhzTGVtb25hZGUvT3BlblBCVEEtYW5hbHlzaXMvNTg2ZDg3OGIyNWM4MDQ5NWEyNTQxMjkyYzJkOWIyODkxNjdmNmVjOS9maWd1cmVzL3BuZ3MvZmlndXJlUzYucG5nKQoKIyMgQXNzZXNzIHBsb3RzCgpOb3csIHdlIHdpbGwgcmUtYXNzZXNzIHNwZWNpZmljIHJlc3VsdHMgd2UgcmVwb3J0IGluIHRoZSBtYW51c2NyaXB0LiAKU3BlY2lmaWNhbGx5LCB0aGVzZSBhcmUgdGhlIHBhcnRzIG9mIHRoZSBtYW51c2NyaXB0IHNlbnRlbmNlcyBiZWxvdyB0aGF0IHJlZmVyZW5jZSBlaXRoZXIgRmlndXJlIDVDIG9yIEZpZ3VyZSBTNkYuCgojIyMgUmVzdWx0IDEKCmh0dHBzOi8vZ2l0aHViLmNvbS9BbGV4c0xlbW9uYWRlL09wZW5QQlRBLW1hbnVzY3JpcHQvYmxvYi9iMGZkZjZmMjRmZTljMDIxZjIyZThiN2RhMzQ4NzA4ZjY4ODc3ZWU1L2NvbnRlbnQvMDMucmVzdWx0cy5tZD9wbGFpbj0xI0wyNzctTDI3OAoKCj4gU2Nod2Fubm9tYXMgYW5kIG5ldXJvZmlicm9tYXMsIHdoaWNoIGhhdmUgYSBkb2N1bWVudGVkIGluZmxhbW1hdG9yeSBpbW11bmUgbWljcm9lbnZpcm9ubWVudCBvZiBUIGFuZCBCIGx5bXBob2N5dGVzIGFzIHdlbGwgYXMgdHVtb3ItYXNzb2NpYXRlZCBtYWNyb3BoYWdlcyAoVEFNcyksIGFyZSBkcml2ZW4gYnkgdXByZWd1bGF0aW9uIG9mIGN5dG9raW5lcyBzdWNoIGFzIElGTiRcZ2FtbWEkLCBJTC0xLCBhbmQgSUwtNiwgYW5kIFRORiRcYWxwaGEkIFtAZG9pOjEwLjEwOTMvbm9ham5sL3ZkYWEwMjNdLgo+IEluZGVlZCwgd2Ugb2JzZXJ2ZWQgc2lnbmlmaWNhbnQgdXByZWd1bGF0aW9uIG9mIHRoZXNlIGN5dG9raW5lcyBpbiBHU1ZBIGhhbGxtYXJrIHBhdGh3YXlzIChCb25mZXJyb25pLWNvcnJlY3RlZCBwIDwgMC4wNSkgKCoqRmlndXJlIHtAZmlnOkZpZzV9QioqKSBhbmQgZm91bmQgaW1tdW5lIGNlbGwgdHlwZXMgZG9taW5hdGVkIGJ5IG1vbm9jeXRlcyBpbiB0aGVzZSB0dW1vcnMgKCoqRmlndXJlIHtAZmlnOkZpZzV9QyoqKS4KCgpUaGUgZmlyc3QgcGxvdCBhYm92ZSByZWNhcGl0dWxhdGVzIHRoZSByZXN1bHQgdGhhdCBtb25vY3l0ZXMgYXJlIGRvbWluYW50IGluIHNjaHdhbm5vbWFzIGFuZCBuZXVyb2ZpYnJvbWFzLgpUaGUgdGhyZXNob2xkZWQgcmVzdWx0cyBhcmUgY29uc2lzdGVudC4KCgojIyMgUmVzdWx0IDIKCmh0dHBzOi8vZ2l0aHViLmNvbS9BbGV4c0xlbW9uYWRlL09wZW5QQlRBLW1hbnVzY3JpcHQvYmxvYi9iMGZkZjZmMjRmZTljMDIxZjIyZThiN2RhMzQ4NzA4ZjY4ODc3ZWU1L2NvbnRlbnQvMDMucmVzdWx0cy5tZD9wbGFpbj0xI0wyODIKCj4gQWx0aG91Z2ggQ0Q4KyBULWNlbGwgaW5maWx0cmF0aW9uIGFjcm9zcyBhbGwgY2FuY2VyIGdyb3VwcyB3YXMgcXVpdGUgbG93ICgqKkZpZ3VyZSB7QGZpZzpGaWc1fUMqKiksIHdlIG9ic2VydmVkIHNvbWUgc2lnbmFsIGluIHNwZWNpZmljIGNhbmNlciBtb2xlY3VsYXIgc3VidHlwZXMgKEdyb3VwcyAzIGFuZCA0IG1lZHVsbG9ibGFzdG9tYSkgYXMgd2VsbCBhcyBvdXRsaWVyIHR1bW9ycyAoQlJBRi1kcml2ZW4gTEdHLCBCUkFGLWRyaXZlbiBhbmQgd2lsZHR5cGUgZ2FuZ2xpb2dsaW9tYSwgYW5kIENOUyBlbWJyeW9uYWwgTk9TOyAqKkZpZ3VyZSB7QGZpZzpTNn1FKiopCgoKCgpUaGUgZmlyc3QgcGxvdCBzaG93cyB0aGF0IENEOCsgVC1jZWxsIGluZmlsdHJhdGlvbiBhY3Jvc3MgYWxsIGNhbmNlciBncm91cHMgcmVtYWlucyBxdWl0ZSBsb3cuClRoZSBzZWNvbmQgcGxvdCBzaG93cyB0aGUgTUIgMy80IHNpZ25hbCwgYnV0IHRoZXJlIGFyZSBubyBsb25nZXIgYW55IG91dGxpZXJzLgpUaGUgdGhyZXNob2xkZWQgcmVzdWx0cyBhcmUgY29uc2lzdGVudCwgYW5kIGRpZmZlcmVuY2VzIG1heSBiZSBleHBsYWluZWQgYnkgc2FtcGxlIHNpemUvcG93ZXIuCgoKIyMjIFJlc3VsdCAzCgpodHRwczovL2dpdGh1Yi5jb20vQWxleHNMZW1vbmFkZS9PcGVuUEJUQS1tYW51c2NyaXB0L2Jsb2IvYjBmZGY2ZjI0ZmU5YzAyMWYyMmU4YjdkYTM0ODcwOGY2ODg3N2VlNS9jb250ZW50LzAzLnJlc3VsdHMubWQ/cGxhaW49MSNMMjgzCgo+IFN1cnByaXNpbmdseSwgdGhlIGNsYXNzaWNhbGx5IGltbXVub2xvZ2ljYWxseS1jb2xkIEhHRyBhbmQgRE1HIHR1bW9ycyBbQGRvaToxMC4xMTg2L3M0MDQ3OC0wMTgtMDU1My14OyBAZG9pOjEwLjEwOTMvYnJhaW4vYXdhYjE1NV0gY29udGFpbmVkIGhpZ2hlciBvdmVyYWxsIGZyYWN0aW9ucyBvZiBpbW11bmUgY2VsbHMsIHdoZXJlIG1vbm9jeXRlcywgZGVuZHJpdGljIGNlbGxzLCBhbmQgTksgY2VsbHMgd2VyZSB0aGUgbW9zdCBwcmV2YWxlbnQgKCoqRmlndXJlIHtAZmlnOkZpZzV9QyoqKS4KCgpUaGUgZmlyc3QgcGxvdCBzaG93cyB0aGF0IGZvciBETUcsIG92ZXJhbGwgZnJhY3Rpb25zIGZhbGwgaW4gcmFuZ2VzIHRoYXQgYXJlIGNvbnNpc3RlbnQgd2l0aCBvdGhlciBjYW5jZXIgZ3JvdXBzLCBzbyAiaGlnaGVyIG92ZXJhbGwgZnJhY3Rpb25zIiBhcmUgbm8gbG9uZ2VyIHRoZSBjYXNlLiAKVGhpcyBkaWZmZXJlbmNlIG1heSBiZSBhIGNvbnNlcXVlbmNlIG9mIHJlZHVjZWQgc2FtcGxlIHNpemUgb3ZlcmFsbCBmb3IgdGhpcyByZS1hbmFseXNpcy4KRE1HcyBhcmUgZG9taW5hdGVkIGJ5IG1vbm9jeXRlcywgZGVuZHJpdGljIGNlbGxzLCBhbmQgTksgY2VsbHMsIHdoaWNoIGlzIGNvbnNpc3RlbnQgd2l0aCBwcmV2aW91cyByZXN1bHRzLgoKSG93ZXZlciwgYXMgd2UgZGlkIG5vdCBhY3R1YWxseSBwbG90IG90aGVyIEhHRyBncm91cHMgaGVyZSwgd2UgbWF5IHdpc2ggdG8gcmV2aXNlIHRoaXMgc3RhdGVtZW50IHRvIGZvY3VzIG1vcmUgb24gdGhlIHBhbmVscyB0aGF0IGFyZSBhY3R1YWxseSBpbiB0aGUgcGxvdCBtb3JlIGdlbmVyYWxseS4KCgoKIyMjIFJlc3VsdCA0CgoKaHR0cHM6Ly9naXRodWIuY29tL0FsZXhzTGVtb25hZGUvT3BlblBCVEEtbWFudXNjcmlwdC9ibG9iL2IwZmRmNmYyNGZlOWMwMjFmMjJlOGI3ZGEzNDg3MDhmNjg4NzdlZTUvY29udGVudC8wMy5yZXN1bHRzLm1kP3BsYWluPTEjTDI5MgoKPiBXaGlsZSBhZGFtYW50aW5vbWF0b3VzIGNyYW5pb3BoYXJ5bmdpb21hcyBhbmQgR3JvdXAgMyBhbmQgR3JvdXAgNCBtZWR1bGxvYmxhc3RvbWFzIGhhZCB0aGUgaGlnaGVzdCBDRDgrIHRvIENENCsgVCBjZWxsIHJhdGlvcyAoKipGaWd1cmUge0BmaWc6UzZ9RioqKSwgdmVyeSBmZXcgdHVtb3JzIGhhZCByYXRpb3MgZ3JlYXRlciB0aGFuIDEsIGhpZ2hsaWdodGluZyBhbiB1cmdlbnQgbmVlZCB0byBpZGVudGlmeSBub3ZlbCB0aGVyYXBldXRpY3MgZm9yIHRoZXNlIGltbXVub2xvZ2ljYWxseS1jb2xkIHBlZGlhdHJpYyBicmFpbiB0dW1vcnMgd2l0aCBwb29yIHByb2dub3Npcy4KCgpBcyBub3RlZCwgdGhlIHNlY29uZCBwbG90IGl0c2VsZiBoYXMgZmV3ZXIgc3VidHlwZXMsIHdoaWNoIGlzIGV4cGVjdGVkIHdpdGggYSBmaWx0ZXJlZCBkYXRhc2V0LgpPZiBub3RlLCB0aGUgYENSQU5JTywgQURBTWAgbW9sZWN1bGFyIHN1YnR5cGUgaXMgbm8gbG9uZ2VyIHByZXNlbnQuCldlIGFnYWluIHNlZSB0aGF0IE1CIGdyb3VwcyAzIGFuZCA0IGhhdmUgaGlnaGVyIHZhbHVlcyB3aXRoIG90aGVyIG1vbGVjdWxhciBzdWJ0eXBlcyBhcm91bmQgMCwgd2hpY2ggaXMgY29uc2lzdGVudCB3aXRoIHRoZSBvcmlnaW5hbCByZXN1bHRzLgoKCgojIyBDb25jbHVzaW9ucwoKT3ZlcmFsbCwgYHF1YW5USXNlcWAgcmVzdWx0cyBhcmUgYnJvYWRseSBjb25zaXN0ZW50IGFmdGVyIHRocmVzaG9sZGluZy4KCgojIyBTZXNzaW9uIEluZm8KCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYA==